<template>
  <div class="image-cropper-container">
    <!-- 圆形预览显示 -->
    <div class="preview-circle" @click="showDialog = true">
      <img v-if="previewImage" :src="previewImage" alt="预览图" />
      <div v-else class="placeholder">
        <el-icon :size="40"><Plus /></el-icon>
        <p>点击上传图片</p>
      </div>
    </div>

    <!-- 裁剪对话框 -->
    <el-dialog
      v-model="showDialog"
      title="裁剪图片"
      width="900px"
      :close-on-click-modal="false"
    >
      <div class="cropper-content">
        <!-- 文件上传 -->
        <div v-if="!imageUrl" class="upload-area">
          <el-upload
            :auto-upload="false"
            :show-file-list="false"
            :on-change="handleFileChange"
            accept="image/*"
            drag
          >
            <el-icon class="el-icon--upload"><upload-filled /></el-icon>
            <div class="el-upload__text">
              将文件拖到此处，或<em>点击上传</em>
            </div>
            <template #tip>
              <div class="el-upload__tip">支持 jpg/png 格式图片</div>
            </template>
          </el-upload>
        </div>

        <!-- 裁剪区域 -->
        <div v-else class="cropper-area">
          <div class="cropper-wrapper">
            <vue-cropper
              ref="cropperRef"
              :img="imageUrl"
              :output-size="1"
              :output-type="'png'"
              :info="true"
              :full="false"
              :can-move="true"
              :can-move-box="true"
              :fixed="false"
              :auto-crop="true"
              :center-box="false"
              :high="true"
              :max-img-size="3000"
            />
          </div>
          <div class="control-area">
            <div class="control-section">
              <p class="section-title">裁剪比例：</p>
              <el-radio-group v-model="aspectRatio" @change="changeAspectRatio" size="small">
                <el-radio-button label="free">自由</el-radio-button>
                <el-radio-button label="1:1">1:1</el-radio-button>
                <el-radio-button label="16:9">16:9</el-radio-button>
                <el-radio-button label="4:3">4:3</el-radio-button>
              </el-radio-group>
            </div>

            <div class="control-section">
              <p class="section-title">缩放与旋转：</p>
              <div class="button-group">
                <el-button-group>
                  <el-button size="small" @click="changeScale(1)">
                    <el-icon><ZoomIn /></el-icon>
                  </el-button>
                  <el-button size="small" @click="changeScale(-1)">
                    <el-icon><ZoomOut /></el-icon>
                  </el-button>
                </el-button-group>
                <el-button-group style="margin-left: 10px;">
                  <el-button size="small" @click="rotateLeft">
                    <el-icon><RefreshLeft /></el-icon>
                  </el-button>
                  <el-button size="small" @click="rotateRight">
                    <el-icon><RefreshRight /></el-icon>
                  </el-button>
                </el-button-group>
              </div>
            </div>

            <div class="control-section">
              <p class="section-title">预览效果：</p>
              <div class="preview-round">
                <div :style="previewStyle"></div>
              </div>
            </div>
          </div>
        </div>
      </div>

      <template #footer>
        <div class="dialog-footer">
          <el-button @click="handleCancel">取消</el-button>
          <el-button v-if="imageUrl" @click="handleReselect">重新选择</el-button>
          <el-button v-if="imageUrl" type="primary" @click="handleCrop">
            确定裁剪
          </el-button>
        </div>
      </template>
    </el-dialog>
  </div>
</template>

<script setup>
import { ref, nextTick } from 'vue';
import { Plus, UploadFilled, ZoomIn, ZoomOut, RefreshLeft, RefreshRight } from '@element-plus/icons-vue';
import { ElMessage } from 'element-plus';
import 'vue-cropper/next/dist/index.css';
import { VueCropper } from 'vue-cropper/next';

// 响应式数据
const showDialog = ref(false);
const imageUrl = ref('');
const previewImage = ref('');
const cropperRef = ref(null);
const previewStyle = ref({});
const aspectRatio = ref('free');

// 处理文件选择
const handleFileChange = (file) => {
  const isImage = file.raw.type.startsWith('image/');
  if (!isImage) {
    ElMessage.error('请上传图片格式文件！');
    return;
  }

  const isLt5M = file.raw.size / 1024 / 1024 < 5;
  if (!isLt5M) {
    ElMessage.error('上传图片大小不能超过 5MB！');
    return;
  }

  const reader = new FileReader();
  reader.onload = (e) => {
    imageUrl.value = e.target.result;
    nextTick(() => {
      realTimePreview();
    });
  };
  reader.readAsDataURL(file.raw);
};

// 实时预览
const realTimePreview = () => {
  if (cropperRef.value) {
    cropperRef.value.getCropData((data) => {
      previewStyle.value = {
        width: '200px',
        height: '200px',
        borderRadius: '50%',
        overflow: 'hidden',
        backgroundImage: `url(${data})`,
        backgroundSize: 'cover',
        backgroundPosition: 'center',
      };
    });
  }
};

// 监听裁剪框变化，实时更新预览
const updatePreview = () => {
  const timer = setInterval(() => {
    if (cropperRef.value && imageUrl.value) {
      realTimePreview();
    }
  }, 100);

  setTimeout(() => clearInterval(timer), 30000);
};

// 确定裁剪
const handleCrop = () => {
  if (cropperRef.value) {
    cropperRef.value.getCropData((data) => {
      previewImage.value = data;
      showDialog.value = false;
      ElMessage.success('图片裁剪成功！');
      resetCropper();
    });
  }
};

// 重新选择
const handleReselect = () => {
  resetCropper();
};

// 取消
const handleCancel = () => {
  showDialog.value = false;
  resetCropper();
};

// 重置裁剪器
const resetCropper = () => {
  imageUrl.value = '';
  previewStyle.value = {};
};

// 监听裁剪器变化
const watchCropper = () => {
  if (cropperRef.value) {
    updatePreview();
  }
};

// 当图片加载后开始监听
const onImageLoad = () => {
  nextTick(() => {
    watchCropper();
  });
};

// 改变裁剪比例
const changeAspectRatio = (value) => {
  if (!cropperRef.value) return;

  switch (value) {
    case 'free':
      cropperRef.value.clearCrop();
      nextTick(() => {
        cropperRef.value.startCrop();
      });
      break;
    case '1:1':
      cropperRef.value.changeFixedNumber([1, 1]);
      break;
    case '16:9':
      cropperRef.value.changeFixedNumber([16, 9]);
      break;
    case '4:3':
      cropperRef.value.changeFixedNumber([4, 3]);
      break;
  }

  realTimePreview();
};

// 缩放
const changeScale = (num) => {
  if (!cropperRef.value) return;
  num = num || 1;
  cropperRef.value.changeScale(num);
  realTimePreview();
};

// 左旋转
const rotateLeft = () => {
  if (!cropperRef.value) return;
  cropperRef.value.rotateLeft();
  realTimePreview();
};

// 右旋转
const rotateRight = () => {
  if (!cropperRef.value) return;
  cropperRef.value.rotateRight();
  realTimePreview();
};
</script>

<style scoped>
.image-cropper-container {
  display: inline-block;
}

.preview-circle {
  width: 200px;
  height: 200px;
  border-radius: 50%;
  overflow: hidden;
  border: 2px dashed #d9d9d9;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  transition: border-color 0.3s;
  background-color: #fafafa;
}

.preview-circle:hover {
  border-color: #409eff;
}

.preview-circle img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.placeholder {
  text-align: center;
  color: #8c939d;
}

.placeholder p {
  margin-top: 10px;
  font-size: 14px;
}

.cropper-content {
  min-height: 400px;
}

.upload-area {
  height: 400px;
  display: flex;
  align-items: center;
  justify-content: center;
}

.cropper-area {
  display: flex;
  gap: 20px;
}

.cropper-wrapper {
  flex: 1;
  height: 500px;
  background-color: #f5f5f5;
}

.control-area {
  width: 280px;
  display: flex;
  flex-direction: column;
  gap: 20px;
}

.control-section {
  background-color: #f9f9f9;
  padding: 15px;
  border-radius: 4px;
}

.section-title {
  margin: 0 0 10px 0;
  font-size: 14px;
  font-weight: 600;
  color: #303133;
}

.button-group {
  display: flex;
  flex-wrap: wrap;
  gap: 5px;
}

.preview-round {
  display: flex;
  justify-content: center;
  margin-top: 10px;
}

.preview-round > div {
  border: 1px solid #e4e7ed;
}

.dialog-footer {
  display: flex;
  justify-content: flex-end;
  gap: 10px;
}

:deep(.el-upload-dragger) {
  padding: 40px;
}

:deep(.el-icon--upload) {
  font-size: 67px;
  color: #c0c4cc;
  margin-bottom: 16px;
}
</style>
